﻿namespace S7.Net
{
    using S7.Net.Interfaces;
    using S7.Net.Types;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Net.NetworkInformation;
    using System.Net.Sockets;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;

    public class Plc : IPlc, IDisposable
    {
        private Socket _mSocket;

        public Plc() : this(CpuType.S7400, "localhost", 0, 2, "", null)
        {
        }

        public Plc(CpuType cpu, string ip, short rack, short slot, string name = "", object tag = null)
        {
            this.IP = ip;
            this.CPU = cpu;
            this.Rack = rack;
            this.Slot = slot;
            this.Name = name;
            this.Tag = tag;
        }

        public void Close()
        {
            if ((this._mSocket != null) && this._mSocket.Connected)
            {
                this._mSocket.Close();
            }
        }

        public void Dispose()
        {
            if ((this._mSocket != null) && this._mSocket.Connected)
            {
                this._mSocket.Close();
            }
        }

        public ErrorCode Open()
        {
            byte[] buffer = new byte[0x100];
            try
            {
                if (!this.IsAvailable)
                {
                    throw new Exception();
                }
            }
            catch
            {
                this.LastErrorCode = ErrorCode.IPAddressNotAvailable;
                this.LastErrorString = string.Format("Destination IP-Address '{0}' is not available!", this.IP);
                return this.LastErrorCode;
            }
            try
            {
                this._mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                this._mSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 0x3e8);
                this._mSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 0x3e8);
                IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse(this.IP), 0x66);
                this._mSocket.Connect(remoteEP);
            }
            catch (Exception exception)
            {
                this.LastErrorCode = ErrorCode.ConnectionError;
                this.LastErrorString = exception.Message;
                return ErrorCode.ConnectionError;
            }
            try
            {
                byte[] buffer2 = new byte[] { 
                    3, 0, 0, 0x16, 0x11, 0xe0, 0, 0, 0, 1, 0, 0xc1, 2, 1, 0, 0xc2, 
                    2, 3, 0, 0xc0, 1, 9
                 };
                switch (this.CPU)
                {
                    case CpuType.S7400:
                        buffer2[11] = 0xc1;
                        buffer2[12] = 2;
                        buffer2[13] = 1;
                        buffer2[14] = 0;
                        buffer2[15] = 0xc2;
                        buffer2[0x10] = 2;
                        buffer2[0x11] = 3;
                        buffer2[0x12] = (byte) (((this.Rack * 2) * 0x10) + this.Slot);
                        break;

                    case CpuType.S71200:
                    case CpuType.S7300:
                        buffer2[11] = 0xc1;
                        buffer2[12] = 2;
                        buffer2[13] = 1;
                        buffer2[14] = 0;
                        buffer2[15] = 0xc2;
                        buffer2[0x10] = 2;
                        buffer2[0x11] = 3;
                        buffer2[0x12] = (byte) (((this.Rack * 2) * 0x10) + this.Slot);
                        break;

                    case CpuType.S71500:
                        buffer2[11] = 0xc1;
                        buffer2[12] = 2;
                        buffer2[13] = 0x10;
                        buffer2[14] = 2;
                        buffer2[15] = 0xc2;
                        buffer2[0x10] = 2;
                        buffer2[0x11] = 3;
                        buffer2[0x12] = (byte) (((this.Rack * 2) * 0x10) + this.Slot);
                        break;

                    case CpuType.S7200:
                        buffer2[11] = 0xc1;
                        buffer2[12] = 2;
                        buffer2[13] = 0x10;
                        buffer2[14] = 0;
                        buffer2[15] = 0xc2;
                        buffer2[0x10] = 2;
                        buffer2[0x11] = 0x10;
                        buffer2[0x12] = 0;
                        break;

                    default:
                        return ErrorCode.WrongCPU_Type;
                }
                this._mSocket.Send(buffer2, 0x16, SocketFlags.None);
                this.byte_send1 = new byte[buffer2.Length];
                this.byte_send1 = buffer2;
                if (this._mSocket.Receive(buffer, 0x16, SocketFlags.None) != 0x16)
                {
                    throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString());
                }
                this.byte_recv1 = new byte[0x16];
                Array.Copy(buffer, this.byte_recv1, 0x16);
                byte[] buffer3 = new byte[] { 
                    3, 0, 0, 0x19, 2, 240, 0x80, 50, 1, 0, 0, 0xff, 0xff, 0, 8, 0, 
                    0, 240, 0, 0, 3, 0, 3, 1, 0
                 };
                this._mSocket.Send(buffer3, 0x19, SocketFlags.None);
                this.byte_send2 = new byte[buffer3.Length];
                this.byte_send2 = buffer3;
                if (this._mSocket.Receive(buffer, 0x1b, SocketFlags.None) != 0x1b)
                {
                    throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString());
                }
                this.byte_recv2 = new byte[0x1b];
                Array.Copy(buffer, this.byte_recv2, 0x1b);
            }
            catch
            {
                this.LastErrorCode = ErrorCode.ConnectionError;
                this.LastErrorString = string.Format("Couldn't establish the connection to {0}!", this.IP);
                return ErrorCode.ConnectionError;
            }
            return ErrorCode.NoError;
        }

        public object Read(string variable)
        {
            string str = variable.ToUpper().Replace(" ", "");
            try
            {
                int num2;
                int num3;
                BitArray array;
                string[] strArray;
                switch (str.Substring(0, 2))
                {
                    case "DB":
                        strArray = str.Split(new char[] { '.' });
                        if (strArray.Length < 2)
                        {
                            throw new Exception();
                        }
                        break;

                    case "EB":
                        return (byte) this.Read(DataType.Input, 0, int.Parse(str.Substring(2)), VarType.Byte, 1);

                    case "EW":
                        return (ushort) this.Read(DataType.Input, 0, int.Parse(str.Substring(2)), VarType.Word, 1);

                    case "ED":
                        return (uint) this.Read(DataType.Input, 0, int.Parse(str.Substring(2)), VarType.DWord, 1);

                    case "AB":
                        return (byte) this.Read(DataType.Output, 0, int.Parse(str.Substring(2)), VarType.Byte, 1);

                    case "AW":
                        return (ushort) this.Read(DataType.Output, 0, int.Parse(str.Substring(2)), VarType.Word, 1);

                    case "AD":
                        return (uint) this.Read(DataType.Output, 0, int.Parse(str.Substring(2)), VarType.DWord, 1);

                    case "MB":
                        return (byte) this.Read(DataType.Memory, 0, int.Parse(str.Substring(2)), VarType.Byte, 1);

                    case "MW":
                        return (ushort) this.Read(DataType.Memory, 0, int.Parse(str.Substring(2)), VarType.Word, 1);

                    case "MD":
                        return (uint) this.Read(DataType.Memory, 0, int.Parse(str.Substring(2)), VarType.DWord, 1);

                    default:
                    {
                        DataType input;
                        switch (str.Substring(0, 1))
                        {
                            case "E":
                            case "I":
                                input = DataType.Input;
                                break;

                            case "A":
                            case "O":
                                input = DataType.Output;
                                break;

                            case "M":
                                input = DataType.Memory;
                                break;

                            case "T":
                                return (double) this.Read(DataType.Timer, 0, int.Parse(str.Substring(1)), VarType.Timer, 1);

                            case "Z":
                            case "C":
                                return (ushort) this.Read(DataType.Counter, 0, int.Parse(str.Substring(1)), VarType.Counter, 1);

                            default:
                                throw new Exception();
                        }
                        string str3 = str.Substring(1);
                        if (str3.IndexOf(".") == -1)
                        {
                            throw new Exception();
                        }
                        num2 = int.Parse(str3.Substring(0, str3.IndexOf(".")));
                        num3 = int.Parse(str3.Substring(str3.IndexOf(".") + 1));
                        if (num3 > 7)
                        {
                            throw new Exception();
                        }
                        byte num13 = (byte) this.Read(input, 0, num2, VarType.Byte, 1);
                        array = new BitArray(new byte[] { num13 });
                        return array[num3];
                    }
                }
                int db = int.Parse(strArray[0].Substring(2));
                string str2 = strArray[1].Substring(0, 3);
                int startByteAdr = int.Parse(strArray[1].Substring(3));
                string str4 = str2;
                if (str4 == null)
                {
                    goto Label_0280;
                }
                if (!(str4 == "DBB"))
                {
                    if (str4 == "DBW")
                    {
                        return (ushort) this.Read(DataType.DataBlock, db, startByteAdr, VarType.Word, 1);
                    }
                    if (str4 == "DBD")
                    {
                        return (uint) this.Read(DataType.DataBlock, db, startByteAdr, VarType.DWord, 1);
                    }
                    if (str4 == "DBX")
                    {
                        goto Label_021F;
                    }
                    goto Label_0280;
                }
                return (byte) this.Read(DataType.DataBlock, db, startByteAdr, VarType.Byte, 1);
            Label_021F:
                num2 = startByteAdr;
                num3 = int.Parse(strArray[2]);
                if (num3 > 7)
                {
                    throw new Exception();
                }
                byte num12 = (byte) this.Read(DataType.DataBlock, db, num2, VarType.Byte, 1);
                array = new BitArray(new byte[] { num12 });
                return array[num3];
            Label_0280:
                throw new Exception();
            }
            catch
            {
                this.LastErrorCode = ErrorCode.WrongVarFormat;
                this.LastErrorString = "The variable'" + variable + "' could not be read. Please check the syntax and try again.";
                return this.LastErrorCode;
            }
        }

        public object Read(DataType dataType, int db, int startByteAdr, VarType varType, int varCount)
        {
            byte[] bytes = null;
            int count = 0;
            switch (varType)
            {
                case VarType.Byte:
                    count = varCount;
                    if (count < 1)
                    {
                        count = 1;
                    }
                    bytes = this.ReadBytes(dataType, db, startByteAdr, count);
                    if (bytes == null)
                    {
                        return null;
                    }
                    if (varCount == 1)
                    {
                        return bytes[0];
                    }
                    return bytes;

                case VarType.Word:
                    count = varCount * 2;
                    bytes = this.ReadBytes(dataType, db, startByteAdr, count);
                    if (bytes != null)
                    {
                        if (varCount == 1)
                        {
                            return Word.FromByteArray(bytes);
                        }
                        return Word.ToArray(bytes);
                    }
                    return null;

                case VarType.DWord:
                    count = varCount * 4;
                    bytes = this.ReadBytes(dataType, db, startByteAdr, count);
                    if (bytes != null)
                    {
                        if (varCount == 1)
                        {
                            return DWord.FromByteArray(bytes);
                        }
                        return DWord.ToArray(bytes);
                    }
                    return null;

                case VarType.Int:
                    count = varCount * 2;
                    bytes = this.ReadBytes(dataType, db, startByteAdr, count);
                    if (bytes != null)
                    {
                        if (varCount == 1)
                        {
                            return Int.FromByteArray(bytes);
                        }
                        return Int.ToArray(bytes);
                    }
                    return null;

                case VarType.DInt:
                    count = varCount * 4;
                    bytes = this.ReadBytes(dataType, db, startByteAdr, count);
                    if (bytes != null)
                    {
                        if (varCount == 1)
                        {
                            return DInt.FromByteArray(bytes);
                        }
                        return DInt.ToArray(bytes);
                    }
                    return null;

                case VarType.Real:
                    count = varCount * 4;
                    bytes = this.ReadBytes(dataType, db, startByteAdr, count);
                    if (bytes != null)
                    {
                        if (varCount == 1)
                        {
                            return S7.Net.Types.Double.FromByteArray(bytes);
                        }
                        return S7.Net.Types.Double.ToArray(bytes);
                    }
                    return null;

                case VarType.String:
                    count = varCount;
                    bytes = this.ReadBytes(dataType, db, startByteAdr, count);
                    if (bytes != null)
                    {
                        return S7.Net.Types.String.FromByteArray(bytes);
                    }
                    return null;

                case VarType.Timer:
                    count = varCount * 2;
                    bytes = this.ReadBytes(dataType, db, startByteAdr, count);
                    if (bytes != null)
                    {
                        if (varCount == 1)
                        {
                            return S7.Net.Types.Timer.FromByteArray(bytes);
                        }
                        return S7.Net.Types.Timer.ToArray(bytes);
                    }
                    return null;

                case VarType.Counter:
                    count = varCount * 2;
                    bytes = this.ReadBytes(dataType, db, startByteAdr, count);
                    if (bytes != null)
                    {
                        if (varCount == 1)
                        {
                            return Counter.FromByteArray(bytes);
                        }
                        return Counter.ToArray(bytes);
                    }
                    return null;
            }
            return null;
        }

        public byte[] ReadBytes(DataType dataType, int DB, int startByteAdr, int count)
        {
            byte[] buffer = new byte[count];
            try
            {
                int size = 0x1f;
                ByteArray array = new ByteArray(size);
                byte[] items = new byte[3];
                items[0] = 3;
                array.Add(items);
                array.Add((byte) size);
                array.Add(new byte[] { 
                    2, 240, 0x80, 50, 1, 0, 0, 0, 0, 0, 14, 0, 0, 4, 1, 0x12, 
                    10, 0x10
                 });
                switch (dataType)
                {
                    case DataType.Counter:
                    case DataType.Timer:
                        array.Add((byte) dataType);
                        break;

                    default:
                        array.Add((byte) 2);
                        break;
                }
                array.Add(Word.ToByteArray((ushort) count));
                array.Add(Word.ToByteArray((ushort) DB));
                array.Add((byte) dataType);
                int num2 = (int) (((long) (startByteAdr * 8)) / 0xffffL);
                array.Add((byte) num2);
                switch (dataType)
                {
                    case DataType.Counter:
                    case DataType.Timer:
                        array.Add(Word.ToByteArray((ushort) startByteAdr));
                        break;

                    default:
                        array.Add(Word.ToByteArray((ushort) (startByteAdr * 8)));
                        break;
                }
                this._mSocket.Send(array.array, array.array.Length, SocketFlags.None);
                this.byte_send1 = new byte[array.array.Length];
                this.byte_send1 = array.array;
                byte[] buffer2 = new byte[0x200];
                int length = this._mSocket.Receive(buffer2, 0x200, SocketFlags.None);
                this.byte_recv1 = new byte[length];
                Array.Copy(buffer2, this.byte_recv1, length);
                if (buffer2[0x15] != 0xff)
                {
                    throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString());
                }
                for (int i = 0; i < count; i++)
                {
                    buffer[i] = buffer2[i + 0x19];
                }
                return buffer;
            }
            catch (SocketException exception)
            {
                this.LastErrorCode = ErrorCode.WriteData;
                this.LastErrorString = exception.Message;
                return null;
            }
            catch (Exception exception2)
            {
                this.LastErrorCode = ErrorCode.WriteData;
                this.LastErrorString = exception2.Message;
                return null;
            }
        }

        public void ReadClass(object sourceClass, int db)
        {
            this.ReadClass(sourceClass, db, 0);
        }

        public void ReadClass(object sourceClass, int db, int startByteAdr)
        {
            Type classType = sourceClass.GetType();
            int classSize = Class.GetClassSize(classType);
            Class.FromBytes(sourceClass, classType, this.ReadMultipleBytes(classSize, db, startByteAdr).ToArray());
        }

        private List<byte> ReadMultipleBytes(int numBytes, int db)
        {
            return this.ReadMultipleBytes(numBytes, db, 0);
        }

        private List<byte> ReadMultipleBytes(int numBytes, int db, int startByteAdr)
        {
            int num2;
            List<byte> list = new List<byte>();
            for (int i = startByteAdr; numBytes > 0; i += num2)
            {
                num2 = Math.Min(numBytes, 200);
                byte[] collection = (byte[]) this.Read(DataType.DataBlock, db, i, VarType.Byte, num2);
                if (collection == null)
                {
                    return new List<byte>();
                }
                list.AddRange(collection);
                numBytes -= num2;
            }
            return list;
        }

        public object ReadStruct(Type structType, int db)
        {
            return this.ReadStruct(structType, db, 0);
        }

        public object ReadStruct(Type structType, int db, int startByteAdr)
        {
            int structSize = Struct.GetStructSize(structType);
            List<byte> list = this.ReadMultipleBytes(structSize, db, startByteAdr);
            return Struct.FromBytes(structType, list.ToArray());
        }

        public object Write(string variable, object value)
        {
            string str2 = variable.ToUpper().Replace(" ", "");
            try
            {
                int num2;
                int num3;
                object obj2;
                string[] strArray;
                switch (str2.Substring(0, 2))
                {
                    case "DB":
                        strArray = str2.Split(new char[] { '.' });
                        if (strArray.Length < 2)
                        {
                            throw new Exception();
                        }
                        break;

                    case "EB":
                        obj2 = Convert.ChangeType(value, typeof(byte));
                        return this.Write(DataType.Input, 0, int.Parse(str2.Substring(2)), (byte) obj2);

                    case "EW":
                        obj2 = Convert.ChangeType(value, typeof(ushort));
                        return this.Write(DataType.Input, 0, int.Parse(str2.Substring(2)), (ushort) obj2);

                    case "ED":
                        obj2 = Convert.ChangeType(value, typeof(uint));
                        return this.Write(DataType.Input, 0, int.Parse(str2.Substring(2)), (uint) obj2);

                    case "AB":
                        obj2 = Convert.ChangeType(value, typeof(byte));
                        return this.Write(DataType.Output, 0, int.Parse(str2.Substring(2)), (byte) obj2);

                    case "AW":
                        obj2 = Convert.ChangeType(value, typeof(ushort));
                        return this.Write(DataType.Output, 0, int.Parse(str2.Substring(2)), (ushort) obj2);

                    case "AD":
                        obj2 = Convert.ChangeType(value, typeof(uint));
                        return this.Write(DataType.Output, 0, int.Parse(str2.Substring(2)), (uint) obj2);

                    case "MB":
                        obj2 = Convert.ChangeType(value, typeof(byte));
                        return this.Write(DataType.Memory, 0, int.Parse(str2.Substring(2)), (byte) obj2);

                    case "MW":
                        obj2 = Convert.ChangeType(value, typeof(ushort));
                        return this.Write(DataType.Memory, 0, int.Parse(str2.Substring(2)), (ushort) obj2);

                    case "MD":
                        return this.Write(DataType.Memory, 0, int.Parse(str2.Substring(2)), value);

                    default:
                    {
                        DataType input;
                        switch (str2.Substring(0, 1))
                        {
                            case "E":
                            case "I":
                                input = DataType.Input;
                                break;

                            case "A":
                            case "O":
                                input = DataType.Output;
                                break;

                            case "M":
                                input = DataType.Memory;
                                break;

                            case "T":
                                return this.Write(DataType.Timer, 0, int.Parse(str2.Substring(1)), (double) value);

                            case "Z":
                            case "C":
                                return this.Write(DataType.Counter, 0, int.Parse(str2.Substring(1)), (short) value);

                            default:
                                throw new Exception(string.Format("Unknown variable type {0}.", str2.Substring(0, 1)));
                        }
                        string str = str2.Substring(1);
                        int index = str.IndexOf(".");
                        if (index == -1)
                        {
                            throw new Exception(string.Format("Cannot parse variable {0}. Input, Output, Memory Address, Timer, and Counter types require bit-level addressing (e.g. I0.1).", str));
                        }
                        num2 = int.Parse(str.Substring(0, index));
                        num3 = int.Parse(str.Substring(index + 1));
                        if (num3 > 7)
                        {
                            throw new Exception(string.Format("Addressing Error: You can only reference bitwise locations 0-7. Address {0} is invalid", num3));
                        }
                        byte num4 = (byte) this.Read(input, 0, num2, VarType.Byte, 1);
                        if (((int) value) == 1)
                        {
                            num4 = (byte) (num4 | ((byte) Math.Pow(2.0, (double) num3)));
                        }
                        else
                        {
                            num4 = (byte) (num4 & (num4 ^ ((byte) Math.Pow(2.0, (double) num3))));
                        }
                        return this.Write(input, 0, num2, num4);
                    }
                }
                int db = int.Parse(strArray[0].Substring(2));
                string str3 = strArray[1].Substring(0, 3);
                int startByteAdr = int.Parse(strArray[1].Substring(3));
                string str4 = str3;
                if (str4 == null)
                {
                    goto Label_0381;
                }
                if (!(str4 == "DBB"))
                {
                    if (str4 == "DBW")
                    {
                        goto Label_01FA;
                    }
                    if (str4 == "DBD")
                    {
                        goto Label_0257;
                    }
                    if (str4 == "DBX")
                    {
                        goto Label_02BF;
                    }
                    if (str4 == "DBS")
                    {
                        return this.Write(DataType.DataBlock, db, startByteAdr, (string) value);
                    }
                    goto Label_0381;
                }
                obj2 = Convert.ChangeType(value, typeof(byte));
                return this.Write(DataType.DataBlock, db, startByteAdr, (byte) obj2);
            Label_01FA:
                if (value is short)
                {
                    obj2 = ((short) value).ConvertToUshort();
                }
                else
                {
                    obj2 = Convert.ChangeType(value, typeof(ushort));
                }
                return this.Write(DataType.DataBlock, db, startByteAdr, (ushort) obj2);
            Label_0257:
                if (value is int)
                {
                    return this.Write(DataType.DataBlock, db, startByteAdr, (int) value);
                }
                obj2 = Convert.ChangeType(value, typeof(uint));
                return this.Write(DataType.DataBlock, db, startByteAdr, (uint) obj2);
            Label_02BF:
                num2 = startByteAdr;
                num3 = int.Parse(strArray[2]);
                if (num3 > 7)
                {
                    throw new Exception(string.Format("Addressing Error: You can only reference bitwise locations 0-7. Address {0} is invalid", num3));
                }
                byte num6 = (byte) this.Read(DataType.DataBlock, db, num2, VarType.Byte, 1);
                if (((int) value) == 1)
                {
                    num6 = (byte) (num6 | ((byte) Math.Pow(2.0, (double) num3)));
                }
                else
                {
                    num6 = (byte) (num6 & (num6 ^ ((byte) Math.Pow(2.0, (double) num3))));
                }
                return this.Write(DataType.DataBlock, db, num2, num6);
            Label_0381:
                throw new Exception(string.Format("Addressing Error: Unable to parse address {0}. Supported formats include DBB (byte), DBW (word), DBD (dword), DBX (bitwise), DBS (string).", str3));
            }
            catch
            {
                this.LastErrorCode = ErrorCode.WrongVarFormat;
                this.LastErrorString = "The variable'" + variable + "' could not be parsed. Please check the syntax and try again.";
                return this.LastErrorCode;
            }
        }

        public object Write(DataType dataType, int db, int startByteAdr, object value)
        {
            byte[] buffer = null;
            switch (value.GetType().Name)
            {
                case "Byte":
                    buffer = S7.Net.Types.Byte.ToByteArray((byte) value);
                    break;

                case "Int16":
                    buffer = Int.ToByteArray((short) value);
                    break;

                case "UInt16":
                    buffer = Word.ToByteArray((ushort) value);
                    break;

                case "Int32":
                    buffer = DInt.ToByteArray((int) value);
                    break;

                case "UInt32":
                    buffer = DWord.ToByteArray((uint) value);
                    break;

                case "Double":
                    buffer = S7.Net.Types.Double.ToByteArray((double) value);
                    break;

                case "Byte[]":
                    buffer = (byte[]) value;
                    break;

                case "Int16[]":
                    buffer = Int.ToByteArray((short[]) value);
                    break;

                case "UInt16[]":
                    buffer = Word.ToByteArray((ushort[]) value);
                    break;

                case "Int32[]":
                    buffer = DInt.ToByteArray((int[]) value);
                    break;

                case "UInt32[]":
                    buffer = DWord.ToByteArray((uint[]) value);
                    break;

                case "Double[]":
                    buffer = S7.Net.Types.Double.ToByteArray((double[]) value);
                    break;

                case "String":
                    buffer = S7.Net.Types.String.ToByteArray(value as string);
                    break;

                default:
                    return ErrorCode.WrongVarFormat;
            }
            return this.WriteBytes(dataType, db, startByteAdr, buffer);
        }

        public ErrorCode WriteBytes(DataType dataType, int db, int startByteAdr, byte[] value)
        {
            byte[] buffer = new byte[0x201];
            int length = 0;
            try
            {
                length = value.Length;
                int size = 0x23 + value.Length;
                ByteArray array = new ByteArray(size);
                byte[] items = new byte[3];
                items[0] = 3;
                array.Add(items);
                array.Add((byte) size);
                array.Add(new byte[] { 2, 240, 0x80, 50, 1, 0, 0 });
                array.Add(Word.ToByteArray((ushort) (length - 1)));
                items = new byte[2];
                items[1] = 14;
                array.Add(items);
                array.Add(Word.ToByteArray((ushort) (length + 4)));
                array.Add(new byte[] { 5, 1, 0x12, 10, 0x10, 2 });
                array.Add(Word.ToByteArray((ushort) length));
                array.Add(Word.ToByteArray((ushort) db));
                array.Add((byte) dataType);
                int num3 = (int) (((long) (startByteAdr * 8)) / 0xffffL);
                array.Add((byte) num3);
                array.Add(Word.ToByteArray((ushort) (startByteAdr * 8)));
                items = new byte[2];
                items[1] = 4;
                array.Add(items);
                array.Add(Word.ToByteArray((ushort) (length * 8)));
                array.Add(value);
                this._mSocket.Send(array.array, array.array.Length, SocketFlags.None);
                this.byte_send1 = new byte[array.array.Length];
                this.byte_send1 = array.array;
                int num4 = this._mSocket.Receive(buffer, 0x200, SocketFlags.None);
                this.byte_recv1 = new byte[num4];
                Array.Copy(buffer, this.byte_recv1, num4);
                if (buffer[0x15] != 0xff)
                {
                    throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString());
                }
                return ErrorCode.NoError;
            }
            catch
            {
                this.LastErrorCode = ErrorCode.WriteData;
                this.LastErrorString = "";
                return this.LastErrorCode;
            }
        }

        public ErrorCode WriteClass(object classValue, int db)
        {
            return this.WriteClass(classValue, db, 0);
        }

        public ErrorCode WriteClass(object classValue, int db, int startByteAdr)
        {
            List<byte> bytes = Class.ToBytes(classValue).ToList<byte>();
            return this.WriteMultipleBytes(bytes, db, startByteAdr);
        }

        private ErrorCode WriteMultipleBytes(List<byte> bytes, int db)
        {
            return this.WriteMultipleBytes(bytes, db, 0);
        }

        private ErrorCode WriteMultipleBytes(List<byte> bytes, int db, int startByteAdr)
        {
            ErrorCode noError = ErrorCode.NoError;
            int num = startByteAdr;
            try
            {
                while (bytes.Count > 0)
                {
                    int count = Math.Min(bytes.Count, 200);
                    noError = this.WriteBytes(DataType.DataBlock, db, num, bytes.ToList<byte>().GetRange(0, count).ToArray());
                    bytes.RemoveRange(0, count);
                    num += count;
                    if (noError != ErrorCode.NoError)
                    {
                        return noError;
                    }
                }
            }
            catch
            {
                this.LastErrorCode = ErrorCode.WriteData;
                this.LastErrorString = "An error occurred while writing data.";
            }
            return noError;
        }

        public ErrorCode WriteStruct(object structValue, int db)
        {
            return this.WriteStruct(structValue, db, 0);
        }

        public ErrorCode WriteStruct(object structValue, int db, int startByteAdr)
        {
            List<byte> bytes = Struct.ToBytes(structValue).ToList<byte>();
            return this.WriteMultipleBytes(bytes, db, startByteAdr);
        }

        public byte[] byte_recv1 { get; set; }

        public byte[] byte_recv2 { get; set; }

        public byte[] byte_send1 { get; set; }

        public byte[] byte_send2 { get; set; }

        public CpuType CPU { get; set; }

        public string IP { get; set; }

        public bool IsAvailable
        {
            get
            {
                using (Ping ping = new Ping())
                {
                    PingReply reply;
                    try
                    {
                        reply = ping.Send(this.IP);
                    }
                    catch (PingException)
                    {
                        reply = null;
                    }
                    return ((reply != null) && (reply.Status == IPStatus.Success));
                }
            }
        }

        public bool IsConnected
        {
            get
            {
                try
                {
                    if (this._mSocket == null)
                    {
                        return false;
                    }
                    return ((!this._mSocket.Poll(0x3e8, SelectMode.SelectRead) || (this._mSocket.Available != 0)) && this._mSocket.Connected);
                }
                catch
                {
                    return false;
                }
            }
        }

        public ErrorCode LastErrorCode { get; private set; }

        public string LastErrorString { get; private set; }

        public string Name { get; set; }

        public short Rack { get; set; }

        public short Slot { get; set; }

        public object Tag { get; set; }
    }
}

